package sms

import (
	"auth-service/internal/dto/sms"
	"auth-service/internal/global"
	"errors"
	"fmt"
	"github.com/danfwing/sd-project/pkg/utils"
	"math/rand"
	"time"
)

const (
	// 验证码长度
	codeLength = 6
	// 验证码有效期（分钟）
	codeExpiration = 5
	// Redis key 前缀
	redisKeyPrefix = "sms:code:"
	// 同一手机号发送间隔（秒）
	sendInterval = 60
)

type SmsService struct{}

// generateCode 生成验证码
func (s *SmsService) generateCode() string {
	// 生成6位数字验证码
	code := rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000000)
	return fmt.Sprintf("%06d", code)
}

// getRedisKey 获取Redis key
func (s *SmsService) getRedisKey(phone, scene string) string {
	return fmt.Sprintf("%s%s:%s", redisKeyPrefix, scene, phone)
}

// SendCode 发送验证码
func (s *SmsService) SendCode(req *sms.SendSmsRequest) (*sms.SmsResponse, error) {
	// 检查发送间隔
	key := s.getRedisKey(req.Phone, req.Scene)
	exists, err := global.GRedis.Exists(global.Ctx, key).Result()
	if err != nil {
		return nil, fmt.Errorf("check redis key error: %v", err)
	}
	if exists == 1 {
		ttl, err := global.GRedis.TTL(global.Ctx, key).Result()
		if err != nil {
			return nil, fmt.Errorf("get redis ttl error: %v", err)
		}
		if ttl.Seconds() > float64(codeExpiration*60-sendInterval) {
			return nil, fmt.Errorf("please wait %d seconds before sending again", sendInterval)
		}
	}

	// 生成验证码
	code := s.generateCode()

	// TODO: 实际发送短信的逻辑，这里先模拟
	// 实际项目中，这里应该调用短信服务商的API
	fmt.Printf("Send SMS to %s: Your verification code is %s\n", req.Phone, code)

	// 存储验证码到Redis
	err = global.GRedis.Set(global.Ctx, key, code, time.Duration(codeExpiration)*time.Minute).Err()
	if err != nil {
		return nil, fmt.Errorf("save code to redis error: %v", err)
	}

	return &sms.SmsResponse{
		RequestId: utils.GenerateUUID(),
		ExpireIn:  codeExpiration * 60,
	}, nil
}

// VerifyCode 验证验证码
func (s *SmsService) VerifyCode(req *sms.VerifySmsRequest) error {
	key := s.getRedisKey(req.Phone, req.Scene)

	// 从Redis获取验证码
	code, err := global.GRedis.Get(global.Ctx, key).Result()
	if err != nil {
		return errors.New("verification code expired or not found")
	}

	// 验证码比对
	if code != req.Code {
		return errors.New("invalid verification code")
	}

	// 验证成功后删除验证码
	err = global.GRedis.Del(global.Ctx, key).Err()
	if err != nil {
		return fmt.Errorf("delete code from redis error: %v", err)
	}

	return nil
}

// CheckCode 检查验证码是否正确（不删除验证码）
func (s *SmsService) CheckCode(phone, scene, code string) error {
	key := s.getRedisKey(phone, scene)

	// 从Redis获取验证码
	savedCode, err := global.GRedis.Get(global.Ctx, key).Result()
	if err != nil {
		return errors.New("verification code expired or not found")
	}

	// 验证码比对
	if savedCode != code {
		return errors.New("invalid verification code")
	}

	return nil
}
